; 编写、安装中断7ch的中断例程
; 求一个word类似数据的平方
; 输入：(ax)=要计算的数据
; 输出：dx,ax存放结果的高、低16位
assume cs:codesg

codesg_sqrt segment
    ; 计算2*3456^2 
    mov ax,3456
    int 7ch
    add ax,ax
    adc dx,dx
    mov ax,4c00h
    int 21h
codesg_sqrt ends

codeSqrSg segment
install:    mov ax,cs
            mov ds,ax
            mov si,offset sqr
            mov ax,0
            mov es,ax
            mov di,200h
            mov cx offset sqrend - offset sqr
            cld
            rep movsb
            mov ax,0
            mov es,ax
            mov word ptr es:[7ch*4],200h
            mov word ptr es:[7ch*4+2],0h
            mov ax,4c00h
            int 21h
sqr:        mul ax
            ; 中断处理程序返回
            iret
sqrend:     nop
codeSqrSg ends

datasg segment
    db 'Are you Ok?',0
datasg ends

codesg_upper segment
; 将一个以0结尾的字符串的，转化为大写
; 参数：ds：si指向字符串的首地址
    mov ax,datasg
    mov ds,ax
    mov si,0
    int 7ch
    mov ax,4c00h
    int 21h
codesg_upper ends

codeUpperSg segment
install:    mov ax,cs
            mov ds,ax
            mov si,offset upper
            mov ax,0
            mov es,ax
            mov di,200h
            mov cx,offset upperend - offset upper
            cld
            rep movsb

            mov ax,0h
            mov es,ax
            mov word ptr es:[7ch*4],200h
            mov word ptr es:[7ch*4+2],0h
            mov ax,4c00h
            int 21h
upper:      
            pushf
            push cx
            push si
change:     
            mov cl,ds:[si]
            mov ch,0h
            jcxz upperOk
            ; 判断是否为字母 'a'<cx<'z' 97~122
            cmp cx,'a'
            jb continue
            cmp cx,'z'
            ja continue
            ; 转化为大写
            and byte ptr ds:[si],11011111B
continue:
            inc si
            jmp short change

upperOk:    
            pop si
            pop cx
            popf
            iret
upperend:   nop

codeUpperSg ends

; 在指定位置显示光标
codesg13 segment
    ; 设置光标
    mov ah,2
    ; 设置显示页号
    mov bh,0
    ; 设置光标行号
    mov dh,5
    ; 设置光标列号
    mov dl,12
    int 10h

    ; 在光标处显示文字
    mov ah,9
    ; 显示的字符
    mov al,'X'
    ; 显示的样式
    mov bl,11001010B
    ; 显示的页号
    mov bh,0
    ; 字符重复次数
    mov cx,5
    int 10h

    mov ax,4c00h
    int 21h
codesg13
end start

; CMOS读写操作
codesg14_2 segment
; 读取CMOS RAM 2号单元内容
c1:     mov al,2
        out 70h,al
        in 71h,al
; 写入CMOS RAM 2号单元内容0
c2:     mov al,2
        out 70h,al
        mov al,0
        out 71h,al
codesg14_2 ends

; 在屏幕中间依次显示a-z，在显示过程中，若按下Esc键则改变显示的颜色
stacksg15 segment
    db 126 dup(0)
stacksg15 ends
datasg15 segment
    dw 0,0
datasg15 ends
codesg15 segment
start: 
        mov ax,stacksg15
        mov ss,ax
        mov sp,128

        mov ax,datasg15
        mov ds,ax

        mov ax,0
        mov es,ax
; 保存原int9例程地址
        cli
        push es:[9*4]
        pop ds:[0]
        push es:[9*4+2]
        pop ds:[2]
        sti
; 修改原int9中断例程地址
        mov word ptr es:[9*4],offset nint9
        mov word ptr es:[9*4+2],cs
; 显示字符a-z
showstr:mov ax,0b800h
        mov es,ax
        mov ah,'a'
s:      mov es:[160*12+40*2],ah
        inc ah
        cmp ah,'z'
        jna s
        mov ax,4c00h
        int 21h
; 延时 CPU循环延时
delay:  push ax
        push dx
        mov dx,1000h
        mov ax,0
s1:     sub ax,1
        sbb dx,0
        cmp ax,0
        jne s1
        cmp dx,0
        jne s1
        pop dx
        pop ax
        ret
; 新int9中断例程
nint9:
        push ax
        push ax
        push es
        ; 取键盘扫描码
        in al,60h
        ; 调用原int9中断例程
        pushf
        call dword ptr ds:[0]
        ; 判断扫描码
        cmp al,1
        jne nint9OK
        ; 修改文字颜色
        mov ax,0b800h
        mov es,ax
        inc byte ptr es:[160*12+40*2+1]
; 新中断返回
nint9OK:
        pop es
        pop bx
        pop ax
        iret
codesg15 ends
; 安装新的int9例程，功能按下F1改变屏幕颜色，按下其他键正常工作
stacksg15_2 segment
    db 128 dup(0)
stacksg15_2 ends
codesg15_2 segment
start:
            mov ax,stacksg15_2
            mov ss,ax
            mov sp,128

            push cs
            pop ds

            mov ax,0
            mov es,ax
            ; 复制int9例程到204h
            mov si,offset nint9
            mov di,204
            mov cx,offset nint9end - offset nint9
            cld
            rep movsb
            ; 保存原有int9例程入口地址到200h
            push es:[9*4]
            pop es:[200h]
            push es:[9*4+2]
            pop es:[202h]
            ; 设置新int9例程入口地址
            cli
            mov word ptr es:[9*4],204h
            mov word ptr es:[9*4+2],0h
            sti
            ; 安装程序退出
            mov ax,4c00h
            int 21h

nint9:      
            push ax
            push bx
            push cx
            push es
            ; 取键盘扫描码
            in al,60h
            ; 调用原int9中断例程
            pushf
            call dword ptr cs:[200h]
            ; 判断扫描码是否为F1
            cmp al,03bh
            jne nint9OK
            ; 改变屏幕颜色
changcolor: 
            mov ax,0b800h
            mov es,ax
            mov bx,1
            mov cx,2000
s:          inc byte ptr es:[bx]
            add bx,2
            loop s

nint9Ok:    
            pop es
            pop cx
            pop bx
            pop ax
            iret
nint9end:   nop
codesg15_2 ends
; 使用十六进制的形式在屏幕中间显示给定的字节型数据
; 输入：一个字节型数据
; 输出：屏幕中间显示2个对应的ASCII码
assume cs:codesg16,ds:datasg16
datasg16 segment
datasg16 ends
codesg16 segment
            mov al,'x'
            call showbyte
            mov ax,4c00h
            int 21h
showbyte:   jmp short show
    table db '0123456789ABCDEF'
show:       push bx
            push es
            mov ah,al
            shr ah,1       
            shr ah,1       
            shr ah,1       
            shr ah,1
            and al,00001111B
            mov bl,ah
            mov bh,0
            mov ah,table[bx]
            mov bx,0b800h
            mov es,bx
            mov es:[160*12+40*2],ah
            mov bl,al
            mov bh,0
            mov al,table[bx]
            mov es:[160*12+40*2+2],al
            pop es
            pop bx
            ret
codesg16 ends
end start

; 字符串输入
; (dh)(dl)=字符串在屏幕上显示的行 列
; ds:si指向字符串的存储空间，字符串以0为结尾
; (ah)=功能号 0-入栈，1-出栈，2-显示
; (ah)=0，(al)=入栈字符
; (ah)=1，(al)=出栈字符
; (ah)=2，(dh),(dl)=字符串在屏幕上显示的行 列位置
stacksg17 segment
        db 128 dup(0)
stacksg17 ends
datasg17 segment
        db 128 dup(0)
datasg17 ends

codesg17 segment

start:
        mov ax,datasg17
        mov ds,ax
        mov si,0

        call getstr

        mov ax,4c00h
        int 21h

; 入栈 出栈 显示字符串的子程序
charstack: jmp short charstart
table   dw charpush,charpop,charshow
top     dw 0 ; 栈顶
charstart:
        push bx
        push dx
        push di
        push es

        cmp ah,2
        ja sret ; ah大于2直接出栈返回
        ; 计算子程序索引由于是dw，所以索引为0 2 4 ，所以需要ah+ah操作
        mov bl,ah
        mov bh,0
        add bx,bx
        jmp word ptr table[bx]
charpush:
        mov bx,top
        mov [si][bx],al ;由于之前指定了ds:si指向字符栈空间，所以ds:[si+bx]指向
        inc top
        jmp sret
charpop:
        cmp top,0
        je sret
        dec top
        mov bx,top
        mov al,[si][bx]
        jmp sret
charshow:
        mov bx,0b800h
        mov es,bx
        mov al,160
        mov ah,0
        mul dh   ; 160*行号
        mov di,ax
        add dl,dl 
        ; 位置=行号*160+列号*2
        add di,dx
        ; 显示的初始位置：es:di
        mov bx,0 ;bx指向栈底
charshows:
        cmp bx,top
        jne noempty
        mov byte ptr es:[di],' '
        jmp sret
noempty:
        mov al,[si][bx]
        mov es:[di],al
        ; 
        mov byte ptr es:[di+2],' '
        inc bx
        add di,2
        jmp charshows
sret:
        pop es
        pop di
        pop dx
        pop bx
        ret
; 接收字符串的子程序
getstr:
        push ax
getstrs:
        mov ah,0
        int 16h
        cmp al,20h
        jb nochar
        mov ah,0
        call charstact
        jmp getstrs
nochar:
        cmp ah,0eh
        je backspace    ;退格键
        cmp ah,1ch
        je enter        ;回车键
        jmp getstrs
backspace:
        mov ah,1
        call charstack
        mov ah,2
        call charstack
        jmp getstrs
enter:
        mov al,0
        mov ah,0
        call charstack
        mov ah,2
        call charstack
        pop ax
        ret
codesg17 ends